package com.nan.gbd.library.extractor;

import android.media.AudioFormat;
import android.media.AudioTrack;
import android.media.MediaFormat;

import com.nan.gbd.library.JNIBridge;
import com.nan.gbd.library.codec.FinishCallback;
import com.nan.gbd.library.codec.GBMediaNative;
import com.nan.gbd.library.codec.MediaCodecConstant;
import com.nan.gbd.library.codec.configuration.VideoConfiguration;
import com.nan.gbd.library.utils.Logger;

import java.nio.ByteBuffer;


public class SimplePlayer implements ExtractorListener {

    private VideoExtractorThread mVideoExtractorThread;
    private AudioExtractorThread mAudioExtractorThread;
    private String filePath;
    private GBMediaNative gbMediaNative;
    private FinishCallback finishCallback;
    private boolean isDownload;

    long startMs;

    public SimplePlayer(String filePath, FinishCallback finishCallback, GBMediaNative gbMediaNative, boolean isDownload) {
        this.finishCallback = finishCallback;
        this.gbMediaNative = gbMediaNative;
        this.filePath = filePath;
        this.isDownload = isDownload;
    }

    /**
     * 是否处于播放状态
     *
     * @return
     */
    public boolean isPlaying() {
        if (mVideoExtractorThread == null) return false;
        return mVideoExtractorThread.isPlaying() && !mVideoExtractorThread.isPause();
    }

    /**
     * 开始播放
     */
    public boolean play() {
        startMs = 0;
        startThread();
        return true;
    }

    private void startThread() {
        if (mVideoExtractorThread == null) {
            mVideoExtractorThread = new VideoExtractorThread(filePath);
            mVideoExtractorThread.setExtractorListener(this);
            mVideoExtractorThread.start();
        }
        if (mAudioExtractorThread == null) {
            mAudioExtractorThread = new AudioExtractorThread(filePath);
            mAudioExtractorThread.setExtractorListener(this);
            mAudioExtractorThread.start();
        }
        MediaCodecConstant.audioStop = false;
        MediaCodecConstant.videoStop = false;
    }

    /**
     * 设置解封装时间点
     *
     * @param seekToUs
     */
    public void setSeekToUs(long seekToUs) {
        if (mVideoExtractorThread != null)
            mVideoExtractorThread.setSeekToUs(seekToUs);
        if (mAudioExtractorThread != null)
            mAudioExtractorThread.setSeekToUs(seekToUs);
    }

    /**
     * 暂停
     */
    public void pause() {
        if (mVideoExtractorThread != null)
            mVideoExtractorThread.setPause(true);
        if (mAudioExtractorThread != null)
            mAudioExtractorThread.setPause(true);
    }

    /**
     * 继续播放
     */
    public void resume() {
        if (mVideoExtractorThread != null)
            mVideoExtractorThread.setPause(false);
        if (mAudioExtractorThread != null)
            mAudioExtractorThread.setPause(false);
    }

    /**
     * 停止播放
     */
    public void stop() {
        destroy();
        finished();
    }

    /**
     * 销毁/释放资源
     */
    private void destroy() {
        isFirst = true;
        packedFileSize = 0;
        if (mAudioExtractorThread != null) {
            mAudioExtractorThread.release();
            mAudioExtractorThread = null;
        }
        if (mVideoExtractorThread != null) {
            mVideoExtractorThread.release();
            mVideoExtractorThread = null;
        }
    }

    private void finished() {
        if (finishCallback != null) {
            finishCallback.onFinished(isDownload ? 4 : 2);
        }
        gbMediaNative = null;
        finishCallback = null;
        filePath = null;
        isDownload = false;
    }


    byte[] mConfigByte;

    @Override
    public void videoAspect(MediaFormat mediaFormat) {
        int width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
        int height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
        float time = mediaFormat.getLong(MediaFormat.KEY_DURATION) / 1000000;
        Logger.e("视频，width:" + width + ",height:" + height + ",duration:" + time + ",文件格式:" + mediaFormat.getString(MediaFormat.KEY_MIME));
        setSps2Pps(mediaFormat);
        readyFinish();
    }

    @Override
    public void audioAspect(MediaFormat mediaFormat) {
        int audioChannels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
        int audioSampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
        int minBufferSize = AudioTrack.getMinBufferSize(audioSampleRate,
                (audioChannels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO),
                AudioFormat.ENCODING_PCM_16BIT);
        int maxInputSize = mediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
        Logger.e("音频，audioChannels:" + audioChannels + ",audioSampleRate:" + audioSampleRate + ",minBufferSize:" + minBufferSize + ",文件格式:" + mediaFormat.getString(MediaFormat.KEY_MIME));
        int mInputBufferSize = minBufferSize > 0 ? minBufferSize * 4 : maxInputSize;
        Logger.e("音频，mInputBufferSize: " + mInputBufferSize);
        if (gbMediaNative != null) {
            gbMediaNative.setAudioFrameLen(mInputBufferSize);
            ready++;
            readyFinish();
        }

    }

    int ready = 0;

    //准备完成，解码线程开始工作
    private void readyFinish() {
        if (ready >= 2) {
            int ret = gbMediaNative.initMuxer(VideoConfiguration.getRecordingConfig());
            Logger.e("sdk音视频封装功能初始化 :" + ret);
            if (ret >= 0) {
                startMs = System.currentTimeMillis();
                Logger.e("video start play time==" + startMs);
                mVideoExtractorThread.setPlaying(true, startMs);
                mAudioExtractorThread.setPlaying(true, startMs);
                ready = 0;
            }
        }
    }

    private void setSps2Pps(MediaFormat mediaFormat) {
        ByteBuffer sps = mediaFormat.getByteBuffer("csd-0");
        ByteBuffer pps = mediaFormat.getByteBuffer("csd-1");

        mConfigByte = new byte[sps.remaining() + pps.remaining()];
        // 转换并打印
        byte[] spsArray = new byte[sps.remaining()];
        byte[] ppsArray = new byte[pps.remaining()];
        sps.get(spsArray);
        pps.get(ppsArray);
        // 输出SPS和PPS
        Logger.e("SPS: " + bytesToHex(spsArray));
        Logger.e("PPS: " + bytesToHex(ppsArray));
        System.arraycopy(spsArray, 0, mConfigByte, 0, spsArray.length);
        System.arraycopy(ppsArray, 0, mConfigByte, spsArray.length, ppsArray.length);
        ready++;
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexBuilder = new StringBuilder();
        for (byte b : bytes) {
            hexBuilder.append(String.format("%02X ", b));
        }
        return hexBuilder.toString();
    }

    long packedFileSize = 0;

    @Override
    public void audioDatas(byte[] audioData) {
        long curTs = System.currentTimeMillis();
        Logger.d("音频流---length:" + audioData.length + "   ts:" + curTs);
        packedFileSize += audioData.length;
        JNIBridge.nanPushAudioFrame(audioData, curTs);
    }


    @Override
    public void endStream() {
        Logger.e("总共上传数据:" + packedFileSize);
        Logger.e("总共播放了多少秒：" + (System.currentTimeMillis() - startMs) / 1000);
        if (isDownload) {
            stop();
        } else {
            destroy();
            play();
        }
    }


    @Override
    public void videoDatas(byte[] videoData, long ts) {
//        FileUtils.writeContent(videoData);
        if (isDownload)
            uploadDownload(videoData, ts);
        else
            uploadPlayBack(videoData, ts);

    }

    private void uploadPlayBack(byte[] videoData, long ts) {
        if (isH264Format(videoData)) {
            byte[] framebytes;
            FrameType frameType = getFrameType(videoData);
            Logger.w("NAL单元 frameType:" + frameType);
            if (mConfigByte == null || mConfigByte.length == 0) return;
            if (frameType == FrameType.I_FRAME) {
                framebytes = new byte[videoData.length + mConfigByte.length];
                System.arraycopy(mConfigByte, 0, framebytes, 0, mConfigByte.length);
                System.arraycopy(videoData, 0, framebytes, mConfigByte.length, videoData.length);
            } else {
                framebytes = new byte[videoData.length];
                System.arraycopy(videoData, 0, framebytes, 0, videoData.length);
            }
            Logger.d("视频流---length:" + framebytes.length + "   ts:" + ts);
            packedFileSize += framebytes.length;
            long nt = System.currentTimeMillis();
            JNIBridge.nanPushVideoFrame(framebytes, nt, frameType == FrameType.I_FRAME);
        }
    }

    boolean isFirst = true;

    private void uploadDownload(byte[] videoData, long ts) {
        if (isH264Format(videoData)) {
            byte[] framebytes;
            FrameType frameType = getFrameType(videoData);
            Logger.w("NAL单元 frameType:" + frameType);
            if (mConfigByte == null || mConfigByte.length == 0) return;
            if (frameType == FrameType.I_FRAME && isFirst) {
                framebytes = new byte[videoData.length + mConfigByte.length];
                System.arraycopy(mConfigByte, 0, framebytes, 0, mConfigByte.length);
                System.arraycopy(videoData, 0, framebytes, mConfigByte.length, videoData.length);
                isFirst = false;
            } else {
                framebytes = new byte[videoData.length];
                System.arraycopy(videoData, 0, framebytes, 0, videoData.length);
            }
            if (isFirst) return;
            packedFileSize += framebytes.length;
            Logger.d("视频流---length:" + framebytes.length + "   ts:" + ts);
            long nt = System.currentTimeMillis();
            JNIBridge.nanPushVideoFrame(framebytes, nt, frameType == FrameType.I_FRAME);
        }
    }

    //     判断NAL单元是否为H264编码格式
    private static boolean isH264Format(byte[] nalUnit) {
//     判断NAL单元头部信息是否为0x00 0x00 0x00 0x01
        if (nalUnit.length >= 4 && nalUnit[0] == 0x00 && nalUnit[1] == 0x00 && nalUnit[2] == 0x00 && nalUnit[3] == 0x01) {
            return true;
        }
        return false;
    }

    /**
     * 00000001后有67,68以及65,41
     * 其中0x67的二进制码为：
     * 0110 0111
     * 4-8为00111，转为十进制7，参考第二幅图：7对应序列参数集SPS
     * <p>
     * 其中0x68的二进制码为：
     * 0110 1000
     * 4-8为01000，转为十进制8，参考第二幅图：8对应图像参数集PPS
     * <p>
     * 其中0x65的二进制码为：
     * 0110 0101
     * 4-8为00101，转为十进制5，参考第二幅图：5对应IDR图像中的片(I帧)
     *
     * @param nalUnit
     * @return
     */
    private static FrameType getFrameType(byte[] nalUnit) {
//     判断NAL单元的第一个字节的后5位
        int nalType = (nalUnit[4] & 0x1F);
        if (nalType == 5) {
            return FrameType.I_FRAME;
        } else if (nalType == 7) {
            return FrameType.SPS_FRAME;
        } else if (nalType == 1 || nalType == 2 || nalType == 3 || nalType == 4 || nalType == 6) {
            return FrameType.B_P_FRAME;
        } else {
            return FrameType.UNKNOWN;
        }
    }

    //     帧类型枚举
    private enum FrameType {
        I_FRAME, SPS_FRAME, B_P_FRAME, UNKNOWN
    }


    /**
     * 获取文件总时长
     *
     * @param filePath
     * @return
     */
    public static float getFileDurationUs(String filePath) {
        VideoExtractorThread mVideoExtractorThread = new VideoExtractorThread(filePath);
        return mVideoExtractorThread.getFileDurationUs();
    }
}
